#include "../../../dxhead/dxegheader.h"
#include "../inc/xmisc.h"
#include <strsafe.h>
using namespace Sky;
namespace Sky
{
	using namespace Sky;
	using namespace Sky::NValue;
#define DXUT_INPUT_DEADZONE                 ( 0.24f * FLOAT(0x7FFF) )  // Default to 24% of the +/- 32767 range.   This is a reasonable default value but can be altered if needed.
#define DXUT_GAMEPAD_TRIGGER_THRESHOLD      30
#define XERR_MEDIANOTFOUND           MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0903)
HMODULE xMisc::s_hModD3D9=vNull;
TChar xMisc::s_strMediaSearchPath[MAX_PATH]={0};
LPDIRECT3DCREATE9 xMisc::s_DynamicDirect3DCreate9=vNull;
TBool xMisc::EnsureD3DAPIs(void)
{
	if(s_hModD3D9!=vNull)return vTrue;
	TChar wszPath[MAX_PATH+1];
	if(!::GetSystemDirectory(wszPath,MAX_PATH+1))return vFalse;
	StringCchCat(wszPath,MAX_PATH,_XT("\\d3d9.dll"));
	s_hModD3D9=LoadLibrary(wszPath);
	if(s_hModD3D9==vNull)return vFalse;
	s_DynamicDirect3DCreate9=(LPDIRECT3DCREATE9)GetProcAddress(s_hModD3D9,_XT("Direct3DCreate9"));
	return vTrue;
}
IDirect3D9 * WINAPI xMisc::Dynamic_Direct3DCreate9(UINT SDKVersion)
{
	if(EnsureD3DAPIs()&&s_DynamicDirect3DCreate9!=vNull)
		return s_DynamicDirect3DCreate9(SDKVersion);
	else
		return vNull;
}

//--------------------------------------------------------------------------------------
TChar* xMisc::GetMediaSearchPath()
{
    return s_strMediaSearchPath;
}
//--------------------------------------------------------------------------------------
HRESULT xMisc::SetMediaSearchPath( TChar* strPath )
{
    HRESULT hr;

    TChar* s_strSearchPath = GetMediaSearchPath();

    hr = StringCchCopy( s_strSearchPath, MAX_PATH, strPath );   
    if( SUCCEEDED(hr) )
    {
        // append slash if needed
        size_t ch;
        hr = StringCchLength( s_strSearchPath, MAX_PATH, &ch );
        if( SUCCEEDED(hr) && s_strSearchPath[ch-1] != _XT('\\'))
        {
            hr = StringCchCat( s_strSearchPath, MAX_PATH, _XT("\\") );
        }
    }

    return hr;
}


//--------------------------------------------------------------------------------------
// Tries to find the location of a SDK media file
//       cchDest is the size in WCHARs of strDestPath.  Be careful not to 
//       pass in sizeof(strDest) on UNICODE builds.
//--------------------------------------------------------------------------------------
HRESULT xMisc::FindDXSDKMediaFileCch( TChar* strDestPath, TInt cchDest, TChar* strFilename )
{
    TBool bFound;
    TChar strSearchFor[MAX_PATH];
    
    if( vNull==strFilename || strFilename[0] == 0 || vNull==strDestPath || cchDest < 10 )
        return E_INVALIDARG;

    // Get the exe name, and exe path
    TChar strExePath[MAX_PATH] = {0};
    TChar strExeName[MAX_PATH] = {0};
    TChar* strLastSlash = vNull;
    GetModuleFileName( vNull, strExePath, MAX_PATH );
    strExePath[MAX_PATH-1]=0;
    strLastSlash = skyStrchr( strExePath, TEXT('\\') );
    if( strLastSlash )
    {
        StringCchCopy( strExeName, MAX_PATH, &strLastSlash[1] );

        // Chop the exe name from the exe path
        *strLastSlash = 0;

        // Chop the .exe from the exe name
        strLastSlash = skyStrchr( strExeName, TEXT('.') );
        if( strLastSlash )
            *strLastSlash = 0;
    }

    // Typical directories:
    //      .\
    //      ..\
    //      ..\..\
    //      %EXE_DIR%\
    //      %EXE_DIR%\..\
    //      %EXE_DIR%\..\..\
    //      %EXE_DIR%\..\%EXE_NAME%
    //      %EXE_DIR%\..\..\%EXE_NAME%

    // Typical directory search
    bFound = FindMediaSearchTypicalDirs( strDestPath, cchDest, strFilename, strExePath, strExeName );
    if( bFound )
        return XE_OK;

    // Typical directory search again, but also look in a subdir called "\media\" 
    StringCchPrintf( strSearchFor, MAX_PATH, _XT("media\\%s"), strFilename ); 
    bFound = FindMediaSearchTypicalDirs( strDestPath, cchDest, strSearchFor, strExePath, strExeName );
    if( bFound )
        return S_OK;

    TChar strLeafName[MAX_PATH] = {0};

    // Search all parent directories starting at .\ and using strFilename as the leaf name
    StringCchCopy( strLeafName, MAX_PATH, strFilename ); 
    bFound = FindMediaSearchParentDirs( strDestPath, cchDest, _XT("."), strLeafName );
    if( bFound )
        return S_OK;

    // Search all parent directories starting at the exe's dir and using strFilename as the leaf name
    bFound = FindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
    if( bFound )
        return S_OK;

    // Search all parent directories starting at .\ and using "media\strFilename" as the leaf name
    StringCchPrintf( strLeafName, MAX_PATH, _XT("media\\%s"), strFilename ); 
    bFound = FindMediaSearchParentDirs( strDestPath, cchDest, _XT("."), strLeafName );
    if( bFound )
        return S_OK;

    // Search all parent directories starting at the exe's dir and using "media\strFilename" as the leaf name
    bFound = FindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
    if( bFound )
        return S_OK;

    // On failure, return the file as the path but also return an error code
    StringCchCopy( strDestPath, cchDest, strFilename );

    return XERR_MEDIANOTFOUND;
}


//--------------------------------------------------------------------------------------
// Search a set of typical directories
//--------------------------------------------------------------------------------------
TBool	xMisc::FindMediaSearchTypicalDirs( TChar* strSearchPath, TInt cchSearch, TChar* strLeaf, TChar* strExePath, TChar* strExeName )
{
    // Typical directories:
    //      .\
    //      ..\
    //      ..\..\
    //      %EXE_DIR%\
    //      %EXE_DIR%\..\
    //      %EXE_DIR%\..\..\
    //      %EXE_DIR%\..\%EXE_NAME%
    //      %EXE_DIR%\..\..\%EXE_NAME%
    //      DXSDK media path

    // Search in .\  
    StringCchCopy( strSearchPath, cchSearch, strLeaf ); 
    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
        return vTrue;

    // Search in ..\  
    StringCchPrintf( strSearchPath, cchSearch, _XT("..\\%s"), strLeaf ); 
    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
        return vTrue;

    // Search in ..\..\ 
    StringCchPrintf( strSearchPath, cchSearch, _XT("..\\..\\%s"), strLeaf ); 
    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
        return vTrue;

    // Search in ..\..\ 
    StringCchPrintf( strSearchPath, cchSearch, _XT("..\\..\\%s"), strLeaf ); 
    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
        return vTrue;

    // Search in the %EXE_DIR%\ 
    StringCchPrintf( strSearchPath, cchSearch, _XT("%s\\%s"), strExePath, strLeaf ); 
    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
        return vTrue;

    // Search in the %EXE_DIR%\..\ 
    StringCchPrintf( strSearchPath, cchSearch, _XT("%s\\..\\%s"), strExePath, strLeaf ); 
    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
        return vTrue;

    // Search in the %EXE_DIR%\..\..\ 
    StringCchPrintf( strSearchPath, cchSearch, _XT("%s\\..\\..\\%s"), strExePath, strLeaf ); 
    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
        return vTrue;

    // Search in "%EXE_DIR%\..\%EXE_NAME%\".  This matches the DirectX SDK layout
    StringCchPrintf( strSearchPath, cchSearch, _XT("%s\\..\\%s\\%s"), strExePath, strExeName, strLeaf ); 
    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
        return vTrue;

    // Search in "%EXE_DIR%\..\..\%EXE_NAME%\".  This matches the DirectX SDK layout
    StringCchPrintf( strSearchPath, cchSearch, _XT("%s\\..\\..\\%s\\%s"), strExePath, strExeName, strLeaf ); 
    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
        return vTrue;

    // Search in media search dir 
    TChar* s_strSearchPath = GetMediaSearchPath();
    if( s_strSearchPath[0] != 0 )
    {
        StringCchPrintf( strSearchPath, cchSearch, _XT("%s%s"), s_strSearchPath, strLeaf ); 
        if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
            return vTrue;
    }

    return vFalse;
}



//--------------------------------------------------------------------------------------
// Search parent directories starting at strStartAt, and appending strLeafName
// at each parent directory.  It stops at the root directory.
//--------------------------------------------------------------------------------------
TBool	xMisc::FindMediaSearchParentDirs( TChar* strSearchPath, TInt cchSearch, TChar* strStartAt, TChar* strLeafName )
{
    TChar strFullPath[MAX_PATH] = {0};
    TChar strFullFileName[MAX_PATH] = {0};
    TChar strSearch[MAX_PATH] = {0};
    TChar* strFilePart = vNull;

    GetFullPathName( strStartAt, MAX_PATH, strFullPath, &strFilePart );
    if( strFilePart == vNull )
        return vFalse;
   
    while( strFilePart != vNull && *strFilePart != '\0' )
    {
        StringCchPrintf( strFullFileName, MAX_PATH, _XT("%s\\%s"), strFullPath, strLeafName ); 
        if( GetFileAttributes( strFullFileName ) != 0xFFFFFFFF )
        {
            StringCchCopy( strSearchPath, cchSearch, strFullFileName ); 
            return vTrue;
        }

        StringCchPrintf( strSearch, MAX_PATH, _XT("%s\\.."), strFullPath ); 
        GetFullPathName( strSearch, MAX_PATH, strFullPath, &strFilePart );
    }

    return vFalse;
}
//void	DisplayErrorMessage(HRESULT hr)
//{
//	TChar strBuffer[256];
//	TInt nExitCode;
//	TBool bFound=vTrue;
//	switch(hr)
//	{
//		case XERR_NODIRECT3D:              nExitCode = 2; StringCchCopy( strBuffer, 256, L"Could not initialize Direct3D. You may want to check that the latest version of DirectX is correctly installed on your system.  Also make sure that this program was compiled with header files that match the installed DirectX DLLs." ); break;
//        case XERR_INCORRECTVERSION:        nExitCode =10; StringCchCopy( strBuffer, 256, L"Incorrect version of Direct3D and/or D3DX." ); break;
//        case XERR_MEDIANOTFOUND:           nExitCode = 4; StringCchCopy( strBuffer, 256, L"Could not find required media. Ensure that the DirectX SDK is correctly installed." ); break;
//        case XERR_NONZEROREFCOUNT:         nExitCode = 5; StringCchCopy( strBuffer, 256, L"The D3D device has a non-zero reference count, meaning some objects were not released." ); break;
//        case XERR_CREATINGDEVICE:          nExitCode = 6; StringCchCopy( strBuffer, 256, L"Failed creating the Direct3D device." ); break;
//        case XERR_RESETTINGDEVICE:         nExitCode = 7; StringCchCopy( strBuffer, 256, L"Failed resetting the Direct3D device." ); break;
//        case XERR_CREATINGDEVICEOBJECTS:   nExitCode = 8; StringCchCopy( strBuffer, 256, L"Failed creating Direct3D device objects." ); break;
//        case XERR_RESETTINGDEVICEOBJECTS:  nExitCode = 9; StringCchCopy( strBuffer, 256, L"Failed resetting Direct3D device objects." ); break;
//		case XERR_NOCOMPATIBLEDEVICES:	   nExitCode = 3; StringCchCopy( strBuffer, 256, L"Could not find any compatible Direct3D devices." );break;
//		case XERR_UNKNOWNERROR:			   nExitCode =1;  StringCchCopy( strBuffer, 256, L"Unknow error.");break;
//		case XERR_MEMORYNOTENOUGH:		   nExitCode =13; StringCchCopy( strBuffer, 256, L"Memory no enough.");break;
//		default:bFound=vFalse;nExitCode=1;break;
//	}
//	{
//			MessageBox(vNull,strBuffer,L"Directx Application",MB_ICONERROR||MB_OK);
//	}
//}

//-----------------------------------------------------------------------------
// Name: HeapCopy()
// Desc: Allocate buffer in memory and copy the content of sName to the
//       buffer, then return the address of the buffer.
//-----------------------------------------------------------------------------
//TChar* xMisc::StringCopy(const TChar *sSour,TUint* count)
//{
//	TUint dwLen;
//	if(count==0)
//	{
//		dwLen= (TUint) xStrLen( sSour ) + 1;	
//	}
//	else if(*count==0)
//	{
//		dwLen= (TUint) xStrLen( sSour ) + 1;	
//		*count=dwLen;
//	}
//	else
//	{
//		dwLen= (TUint) *count;
//	}
//	TChar* Dest = new TChar[ dwLen ];
//	if( Dest )
//		StringCchCopy( Dest, dwLen, sSour );
//	//Dest[dwLen-1]=0;
//	return Dest;
//}

void xMisc::Pick(TInt client_x,TInt client_y,
						TInt back_buffer_width,TInt back_buffer_height,
						const D3DXMATRIX* pmatWorld,
						const D3DXMATRIX* pmatView,
						const D3DXMATRIX* pmatProj, 
						D3DXVECTOR3* pPickRayDir,
						D3DXVECTOR3* pRayOrig)
{
	POINT ptCursor;

	ptCursor.x = client_x;
	ptCursor.y = client_y;
	//ScreenToClient( hwnd, &ptCursor );

	// Compute the vector of the pick ray in screen space
	D3DXVECTOR3 v;
	v.x =  ( ( ( 2.0f * ptCursor.x ) / back_buffer_width  ) - 1 ) / pmatProj->_11;
	v.y = -( ( ( 2.0f * ptCursor.y ) / back_buffer_height ) - 1 ) / pmatProj->_22;
	v.z =  1.0f;

	// Get the inverse view matrix
	D3DXMATRIX mWorldView = *pmatWorld * *pmatView;
	D3DXMATRIX m;
	D3DXMatrixInverse( &m, vNull, &mWorldView );

	// Transform the screen space pick ray TInto 3D space
	pPickRayDir->x  = v.x*m._11 + v.y*m._21 + v.z*m._31;
	pPickRayDir->y  = v.x*m._12 + v.y*m._22 + v.z*m._32;
	pPickRayDir->z  = v.x*m._13 + v.y*m._23 + v.z*m._33;
	if(pRayOrig){
		pRayOrig->x = m._41;
		pRayOrig->y = m._42;
		pRayOrig->z = m._43;
	}
	return ;
}
}